package org.ytor.core.sqlflow.plugin.support;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import org.ytor.common.classmeta.ClassMetadata;
import org.ytor.common.exception.BaseException;
import org.ytor.common.util.Jsons;
import org.ytor.common.util.Strs;
import org.ytor.common.util.cache.ClassCache;
import org.ytor.core.CommonApi;
import org.ytor.core.holder.U;
import org.ytor.core.model.LoginUser;
import org.ytor.core.sqlflow.anno.Table;
import org.ytor.core.sqlflow.builder.support.WhereBuilder;
import org.ytor.core.sqlflow.executor.DQLResult;
import org.ytor.core.sqlflow.executor.SqlExecutor;
import org.ytor.core.sqlflow.plugin.InterceptorAdapter;
import org.ytor.core.sysapi.log.model.SysLog;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * created by yangtong on 2025/8/14 10:36:58
 * <br/>
 * 删除操作时，记录下删除的数据
 */
@Slf4j
@Component
public class RecycleBinInterceptor extends InterceptorAdapter {

    @Lazy
    @Autowired
    private SqlExecutor sqlExecutor;
    @Autowired
    private CommonApi commonApi;


    @Override
    public void beforeDelete(Class<?> tableClass, String tableName, String sql, WhereBuilder where, List<Object> params) {
        // 判断删除该表数据时，是否需要备份
        if (tableClass == null) {
            return;
        }
        ClassMetadata<?> classMetadata = ClassCache.get(tableClass);
        Table tableAnno = classMetadata.getAnnotation(Table.class);
        if (tableAnno == null || !tableAnno.backupOnDelete()) {
            return;
        }

        // 走到这，说明需要备份待删除数据
        LoginUser loginUser = U.get();
        String deleteBy = null;
        if (loginUser != null) {
            deleteBy = loginUser.getUserName();
        }
        LocalDateTime deletedTime = LocalDateTime.now();

        String whereSql = where.toSql();
        try {
            // 删除数据前，先记录下原始数据
            String selectSQL = Strs.format("SELECT * FROM {} {}", tableName, whereSql);

            // 直接通过SQL执行器来进行数据库操作，避免重新走一遍拦截器
            DQLResult DQLResult = sqlExecutor.doQuery(selectSQL, params);

            List<List<Object>> recycleBins = new ArrayList<>();
            String insertSQL = Strs.format("INSERT INTO sys_recycle_bin (deleted_by, deleted_time, delete_reason, original_table, original_id, original_data) VALUES (?, ?, ?, ?, ?, ?)");
            for (Map<String, Object> row : DQLResult.getRows()) {
                List<Object> recycleBin = new ArrayList<>();
                recycleBin.add(deleteBy);
                recycleBin.add(deletedTime);
                recycleBin.add("-");
                recycleBin.add(tableName);
                recycleBin.add(row.get("id"));
                recycleBin.add(Jsons.toJsonStr(row));
                recycleBins.add(recycleBin);
            }

            sqlExecutor.doInsertBatch(insertSQL, recycleBins);

        } catch (Exception e) {
            commonApi.addAsyncLog(() -> new SysLog()
                    .setType(6)
                    .setThread(Thread.currentThread().getName())
                    .setClassName(this.getClass().getName())
                    .setErrorMsg(e.getMessage())
                    .setErrorStack(Arrays.toString(e.getStackTrace()))
                    .setMethodName("beforeBuilder")
                    .setContent(Strs.format("执行DELETE【{}】操作时出错: WHERE 条件{}", whereSql)));
            throw new BaseException("备份待删除数据时出错", e);
        }
    }
}
